package br.com.edoc.util;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.text.ParseException;


import br.com.edoc.enun.util.DiaSemana;

import br.com.edoc.enun.util.UnidadeTempo;
import br.com.edoc.excecoes.DateException;

public class TratamentoData {
	
	public static final DateFormat formatterBrazilianDate = new SimpleDateFormat("dd/MM/yyyy");
	
	public static final DateFormat formatterJDBCDate = new SimpleDateFormat("yyyy-MM-dd");
	
	public static final DateFormat formatterBrazilianTimeSpam = new SimpleDateFormat("dd/MM/yyyy:HH:mm");
	
	public enum CompareData{MAIOR,MENOR,IGUAL};
	
	public static final String converteDateForTimeFrmtBrazilian(java.util.Date dtData) throws DateException{  
		try{
			SimpleDateFormat formatBra;     
			formatBra = new SimpleDateFormat("dd/MM/yyyy:HH:mm");  
			return (formatBra.format(dtData));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			throw new  DateException("Erro ao transformar string em data",e);
		}  
	}
	
	public static final Date converterStringForTimesPamBrazilian(String str) throws DateException{
		try {
			return formatterBrazilianTimeSpam.parse(str);
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			throw new DateException("Erro ao converter Data",e);
		}
	}
	public static final List<Date> getListOfDatesInTimeInterval(Date dataIni,Date dataFim) throws DateException{
		
		List<Date> lista = new ArrayList<>();
		Date currentDate = dataIni;
		lista.add(currentDate);
		while(!TratamentoData.comparaDataSemHorasMinutos(currentDate, dataFim).equals(CompareData.IGUAL)){
			currentDate = incrementaData(currentDate,1, Calendar.DAY_OF_MONTH);
			lista.add(currentDate);
		}
		return lista;
	}
	
	public static final String conveterDateForString(Date date ){
		SimpleDateFormat formatBra;     
		Random ram = new Random();
	    formatBra = new SimpleDateFormat("yyyy-MM-dd_hh_mm_ss"+ram.hashCode());
	    return formatBra.format(date);   
	}
	public static final Date converterStringTimeBrazilianForDateTime(String time){
		String [] horas = time.split(":");
		if(horas.length==2){
			Calendar calendar = Calendar.getInstance();
			calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(horas[0]));
			calendar.set(Calendar.MINUTE, Integer.parseInt(horas[1]));
			calendar.set(Calendar.SECOND,0);
			return calendar.getTime();
		}else{
			return null;
		}
	}
	public static final String converterDateTimeForStringTimeBrazilian(Date time){
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(time);
		return ""+((calendar.get(Calendar.HOUR_OF_DAY)<10)?"0"+calendar.get(Calendar.HOUR_OF_DAY):calendar.get(Calendar.HOUR_OF_DAY))+":"+((calendar.get(Calendar.MINUTE)<10)?"0"+calendar.get(Calendar.MINUTE):calendar.get(Calendar.MINUTE));
	}
	/**
	 * converte uma string no formatro brasileiro (dd/MM/yyyy) para objeto date do java
	 * @param dtData
	 * @return
	 */
	public static final Date converterStringForDateBrazilian(String str) throws DateException{
		try {
			return formatterBrazilianDate.parse(str);
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			throw new DateException("Erro ao converter Data",e);
		}
	}
	/**
	 * @author diegoires
	 * @param data1
	 * @param data2
	 * @return CompareData
	 * @throws DateException
	 * 
	 * este método é responsável por comparar duas data(data1,data2) vindo a retornar o enum CompareData
	 * caso a data1 > data2 return CompareData.MAIOR
	 * caso a data1 < data2 return CompareData.MENOR
	 * caso a data1 == data2 return  CompareData.IGUAL
	 */
	public static final CompareData comparaDataSemHorasMinutos(Date data1,Date data2) throws DateException{
		data1 = converterStringForDateBrazilian(converteDateForDateFrmtBrazilian(data1));
		data2 = converterStringForDateBrazilian(converteDateForDateFrmtBrazilian(data2));
		if (data1.after(converterStringForDateBrazilian(converteDateForDateFrmtBrazilian(data2))))
			return CompareData.MAIOR;
		else if (data1.before(converterStringForDateBrazilian(converteDateForDateFrmtBrazilian(data2))))
			return CompareData.MENOR;
		else	    
			return CompareData.IGUAL;
	}
	
	public static final CompareData comparaHorasMinutos(Date hora1,Date hora2) throws DateException{
		hora1 = converterStringTimeBrazilianForDateTime(converterDateTimeForStringTimeBrazilian(hora1));
		hora2 = converterStringTimeBrazilianForDateTime(converterDateTimeForStringTimeBrazilian(hora2));
		if (hora1.after(converterStringTimeBrazilianForDateTime(converterDateTimeForStringTimeBrazilian(hora2))))
			return CompareData.MAIOR;
		else if (hora1.before(converterStringTimeBrazilianForDateTime(converterDateTimeForStringTimeBrazilian(hora2))))
			return CompareData.MENOR;
		else	    
			return CompareData.IGUAL;
	}
	
	public static final java.sql.Date convertDateUtilForDateSql(java.util.Date data ){
		return new java.sql.Date(data.getTime());
	}
	/**
	 * converte uma data para o formato do banco yyyy-MM-dd
	 * @param dtData
	 * @return
	 */
	public static final String converteDateForDateJDBC(java.util.Date dtData){  
        SimpleDateFormat formatBra;     
        formatBra = new SimpleDateFormat("yyyy-MM-dd");  
        return (formatBra.format(dtData));  
	}
	
	public static final Date converteStringJDBCForDate(String date){
		 try {
			return   (Date)formatterJDBCDate.parse(date);
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			return null;
		}  
	}
	/**
	 * Este método verifica a quantidade de dias entre as datas 
	 * @author diego
	 * @param dataMenor
	 * @param dataMaior
	 * @return quantDias
	 * @throws DateException
	 */
	public static final int obtemQuantidadeDiasEntreDuasDatas(Date dataMenor,Date dataMaior) throws DateException{
		try {
			dataMaior = converterStringForDateBrazilian(converteDateForDateFrmtBrazilian(dataMaior));
			dataMenor = converterStringForDateBrazilian(converteDateForDateFrmtBrazilian(dataMenor));
			return  (int) ((dataMaior.getTime()-dataMenor.getTime())/86400000);
		} catch (DateException e) {
			// TODO Auto-generated catch block
			throw new DateException(e.getMessage());
		}
		
	}
	
	/**
	 * Este método verifica a quantidade de dias entre as datas  incluindo nos dias a menor data
	 * @author diego
	 * @param dataMenor
	 * @param dataMaior
	 * @return quantDias
	 * @throws DateException
	 */
	public static final int obtemQuantidadeDiasEntreDuasDatasComDataIni(Date dataMenor,Date dataMaior) throws DateException{
		try {
			dataMaior = converterStringForDateBrazilian(converteDateForDateFrmtBrazilian(dataMaior));
			dataMenor = converterStringForDateBrazilian(converteDateForDateFrmtBrazilian(TratamentoData.incrementaData(dataMenor, -1,Calendar.DAY_OF_MONTH)));
			return  (int) ((dataMaior.getTime()-dataMenor.getTime())/86400000);
		} catch (DateException e) {
			// TODO Auto-generated catch block
			throw new DateException(e.getMessage());
		}
		
	}
	/**
	 * Este método verifica a quantidade de dias entre as datas  incluindo nos dias a menor data
	 * @author diego
	 * @param dataMenor
	 * @param dataMaior
	 * @return quantDias
	 * @throws DateException
	 */
	public static final int obtemQuantidadeDiasEntreDuasDatasComDataIniFim(Date dataMenor,Date dataMaior) throws DateException{
		try {
			dataMaior = converterStringForDateBrazilian(converteDateForDateFrmtBrazilian(dataMaior));
			dataMenor = converterStringForDateBrazilian(converteDateForDateFrmtBrazilian(TratamentoData.incrementaData(dataMenor, -1,Calendar.DAY_OF_MONTH)));
			return  (int) ((dataMaior.getTime()-dataMenor.getTime())/86400000);
		} catch (DateException e) {
			// TODO Auto-generated catch block
			throw new DateException(e.getMessage());
		}
		
	}
	/**
	 * incrementa data sem incluir a data inícial na contagem  
	 * @param data
	 * @param quantidade
	 * @param tipoIncremento
	 * @return
	 */
	public static final Date incrementaData(Date data,Integer quantidade,Integer tipoIncremento){
		 Calendar calendar = Calendar.getInstance();  
		 calendar.setTime(data);
		   
		  calendar.add(tipoIncremento, quantidade);
		  return calendar.getTime();
		   
	}
	
	/**
	 * pegar o inteiro correspondente ao  dia da semana  <br/>
	 * {"Domingo"=0,"Segunda"=1,"Terça"=2,"Quarta"=3,"Quinta"=4,"Sexta"=5,"Sábado"=6}
	 * @param data
	 * @return
	 */
	public static final int getDiaSemana(Date data){
		 Calendar calendario = Calendar.getInstance();
		 calendario.setTime(data);
		 return calendario.get(Calendar.DAY_OF_WEEK)-1;  
	}
	/**
	 * retorna o nome do dia da semana
	 * pegar o dia da semana 
	 * @param data
	 * @return
	 */
	public static final  DiaSemana getNameDiaSemana(Date data){
		 Calendar calendario = Calendar.getInstance();
		 calendario.setTime(data);
		 return DiaSemana.values()[Calendar.DAY_OF_WEEK];  
	}
	/**
	 * incrementa data incluindo a data inícial na contagem   dos dias
	 * @param data
	 * @param quantidade
	 * @param tipoIncremento
	 * @return
	 */
	public static final Date incrementaWithData(Date data,Integer quantidade,Integer tipoIncremento){
		 Calendar calendar = Calendar.getInstance();  
		 calendar.setTime(TratamentoData.incrementaData(data, -1, Calendar.DAY_OF_MONTH));
		   
		  calendar.add(tipoIncremento, quantidade);
		  return calendar.getTime();
		   
	}
	public static final Date incrementaWithTime(Date time,Integer quantidade,Integer tipoIncremento){
		 Calendar calendar = Calendar.getInstance();
		 calendar.setTime(time);
		 calendar.add(tipoIncremento, quantidade);
		 return calendar.getTime();
		   
	}
	public static double arredondar(double valor, int casas, int ceilOrFloor) {  
	      double arredondado = valor;  
	      arredondado *= (Math.pow(10, casas));  
	      if (ceilOrFloor == 0) {  
	         arredondado = Math.ceil(arredondado);           
	      } else {  
	         arredondado = Math.floor(arredondado);  
	      }  
	      arredondado /= (Math.pow(10, casas));  
	      return arredondado;  
	   } 
	
	public static final long getDiferencaEntreDoisTime(Date hora1,Date hora2,UnidadeTempo unidade){
		float diferenca = TratamentoData.converterStringTimeBrazilianForDateTime(TratamentoData.converterDateTimeForStringTimeBrazilian(hora1)).getTime() - TratamentoData.converterStringTimeBrazilianForDateTime(TratamentoData.converterDateTimeForStringTimeBrazilian(hora2)).getTime();
		if(unidade.equals(UnidadeTempo.SEGUNDO)){
			return (int)(diferenca /1000);
		}else if(unidade.equals(UnidadeTempo.MINUTO)){
			return ((new BigDecimal(diferenca)).divide(new BigDecimal(1000)).divide(new BigDecimal(60),3,BigDecimal.ROUND_UP)).intValue();
		}else if (unidade.equals(UnidadeTempo.HORA)){
			return (((new BigDecimal(diferenca)).divide(new BigDecimal(1000)).divide(new BigDecimal(60),3,BigDecimal.ROUND_UP)).divide(new BigDecimal(60))).intValue();
		}else return 0;
		
		
	}
	
	public static final String converteDateForDateFrmtBrazilian(java.util.Date dtData) throws DateException{  
		try{
		SimpleDateFormat formatBra;     
        formatBra = new SimpleDateFormat("dd/MM/yyyy");  
        return (formatBra.format(dtData));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			throw new DateException(e.getMessage());
		}  
	}
}